package com.bytech.admin.config;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import com.bytech.admin.biz.enums.SystemSettingEnum;
import com.bytech.common.biz.enums.CommonStatusEnum;
import com.bytech.common.biz.enums.ServiceTypeEnum;
import com.bytech.common.biz.enums.friendChain.FriendChainAuditStatusEnum;
import com.bytech.common.config.AppGlobalConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.freemarker.FreeMarkerProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.MimeType;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;

import com.bytech.common.biz.enums.comment.CommentStatusEnum;
import com.bytech.common.utils.DateUtils;
import com.bytech.common.utils.StringUtils;
import com.google.common.collect.ImmutableSet;
import freemarker.ext.beans.BeansWrapper;
import freemarker.ext.beans.BeansWrapperBuilder;
import freemarker.template.TemplateException;
import freemarker.template.TemplateHashModel;

@Configuration
@ComponentScan({"com.bytech.admin.biz.controller", "com.bytech.admin.biz.interceptor"})
public class FreeMarkerConfig {

    @Value("${freemarker.template.templateLocation}")
    private String templateLocation;

    @Value("${freemarker.template.requestContext}")
    private String requestContext;

    @Value("${freemarker.template.contentType}")
    private String contentType;

    @Value("${freemarker.template.cache:true}")
    private Boolean cache;

    @Value("${freemarker.template.suffix}")
    private String suffix;

    @Value("${freemarker.template.prefix}")
    private String prefix;

    @Value("${freemarker.auto_import}")
    private String autoImport;

    @Value("${freemarker.auto_include}")
    private String autoInclude;

    private FreeMarkerProperties properties;

    @Autowired
    private void setFreeMarkerProperties(FreeMarkerProperties pp) {
        properties = pp;
    }

    private final BeansWrapper beansWrapper = new BeansWrapperBuilder(freemarker.template.Configuration.VERSION_2_3_23).build();

    private static final Set<Class<? extends Enum<?>>> SharedEnums = ImmutableSet.of(CommentStatusEnum.class, ServiceTypeEnum.class
            , CommonStatusEnum.class, SystemSettingEnum.class, FriendChainAuditStatusEnum.class);

    private static final Set<Class<?>> SharedStatics = ImmutableSet.of(DateUtils.class, StringUtils.class, AppGlobalConstants.class);

    @Bean
    public FreeMarkerConfigurer freeMarkerConfigurer() throws IOException, TemplateException {
        FreeMarkerConfigurer config = new FreeMarkerConfigurer();
        config.setTemplateLoaderPaths(properties.getTemplateLoaderPath());
        config.setPreferFileSystemAccess(properties.isPreferFileSystemAccess());
        config.setDefaultEncoding(properties.getCharsetName());
        Properties settings = new Properties();
        settings.putAll(properties.getSettings());
        config.setFreemarkerSettings(settings);
        freemarker.template.Configuration configuration = null;
        configuration = config.createConfiguration();
        //自动加载宏
        if (!StringUtils.isBlank(autoImport)) {
            List<String> imports = Arrays.asList(autoImport.split(";"));
            Map<String, String> importMap = new HashMap<String, String>(imports.size());
            imports.stream().forEach(e -> {
                String[] keyValue = e.split("as");
                if (keyValue.length == 2) {
                    importMap.put(keyValue[1].trim(), keyValue[0].trim());
                }
            });
            configuration.setAutoImports(importMap);
        }
        if (!StringUtils.isBlank(autoInclude)) {
            String[] includes = autoInclude.split(";");
            List list = new ArrayList<String>(Arrays.asList(includes));
            configuration.setAutoIncludes(list);
        }
        config.setConfiguration(configuration);

        for (Class<? extends Enum<?>> e : SharedEnums) {
            TemplateHashModel staticModels = beansWrapper.getStaticModels();
            TemplateHashModel statics = (TemplateHashModel) staticModels.get(e.getName());
            if (statics != null) {
                config.getConfiguration().setSharedVariable(e.getSimpleName(), statics);
            }
        }

        for (Class<?> e : SharedStatics) {
            TemplateHashModel staticModels = beansWrapper.getStaticModels();
            TemplateHashModel statics = (TemplateHashModel) staticModels.get(e.getName());
            if (statics != null) {
                config.getConfiguration().setSharedVariable(e.getSimpleName(), statics);
            }
        }

        return config;
    }

    @Bean
    public FreeMarkerViewResolver freeMarkerViewResolver() {
        FreeMarkerViewResolver freeMarkerViewResolver = new FreeMarkerViewResolver();
        FreeMarkerProperties properties = new FreeMarkerProperties();
        properties.setTemplateLoaderPath(templateLocation);
        properties.setSuffix(suffix);
        properties.setPrefix(prefix);
        properties.setContentType(MimeType.valueOf(contentType));
        properties.setCharset(StandardCharsets.UTF_8);
        properties.setCache(cache);
        properties.setAllowRequestOverride(true);
        properties.setAllowSessionOverride(true);
        properties.setRequestContextAttribute(requestContext);
        properties.applyToMvcViewResolver(freeMarkerViewResolver);
        return freeMarkerViewResolver;
    }
}
